// 版权所有2016 etcd作者
// 
// 根据Apache许可证2.0版（以下简称“许可证”）获得许可；
// 除非遵守许可证，否则不得使用此文件。
// 您可以通过
// 
// www.apache.org/licenses/LICENSE-2.0 
// 
// 除非适用法律要求或书面同意，否则根据许可证分发的软件
// 按“原样”分发，
// 无任何明示或暗示的保证或条件。
// 请参阅许可证，了解管理许可的特定语言和
// 许可证下的限制。

// go:build darwin 
// +build darwin 

package fileutil

import (
	"os"
	"syscall"

	"golang.org/x/sys/unix"
)

func preallocExtend(f *os.File, sizeInBytes int64) error {
	if err := preallocFixed(f, sizeInBytes); err != nil {
		return err
	}
	return preallocExtendTrunc(f, sizeInBytes)
}

func preallocFixed(f *os.File, sizeInBytes int64) error {
	// 分配所有请求的空间或完全不分配空间
	// TODO:使用F_ALLOCATECONTIG标志分配磁盘上的连续空间
	fstore := &unix.Fstore_t{
		Flags:   unix.F_ALLOCATEALL,
		Posmode: unix.F_PEOFPOSMODE,
		Length:  sizeInBytes,
	}
	err := unix.FcntlFstore(f.Fd(), unix.F_PREALLOCATE, fstore)
	if err == nil || err == unix.ENOTSUP {
		return nil
	}

	// 挂起系统调用
	if err == unix.EINVAL {
		// 文件系统“st_块”以
		// “分配块大小”（运行“diskutil info/”命令）
		var stat syscall.Stat_t
		syscall.Fstat(int(f.Fd()), &stat)

		// /syscall为单位分配。Statfs_t.Bsize是“最佳传输块大小”
		// 并且在最新的OS X内核
		// 支持4096 KB文件系统块大小
		var statfs syscall.Statfs_t
		syscall.Fstatfs(int(f.Fd()), &statfs)
		blockSize := int64(statfs.Bsize)

		if stat.Blocks*blockSize >= sizeInBytes {
			// 已经分配了足够的块
			return nil
		}
	}
	return err
}
